﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using Server.Properties;

namespace Server
{
    public partial class MainForm : Form
    {
        /// <summary>处理监听客户端连接的线程</summary>
        private readonly Thread _myThread;

        /// <summary>保存连接的所有用户</summary>
        private readonly List<Socket> _userList = new List<Socket>();

        /// <summary>监听客户端连接请求的主socket</summary>
        private Socket _socket;

        public MainForm()
        {
            InitializeComponent();
            string serverIp = ConfigurationManager.ConnectionStrings["serverIP"].ConnectionString;
            string serverPort = ConfigurationManager.ConnectionStrings["serverPort"].ConnectionString;
            StartServer(IPAddress.Parse(serverIp), int.Parse(serverPort));
            txtAddress.Text = serverIp;
            txtPort.Text = serverPort;
            AddTalkMessage(DateTime.Now + "： 开始监听客户连接");
            //创建一个线程监听客户端连接请求
            _myThread = new Thread(ListenClientConnect);
            _myThread.Start();
        }

        private void BtnSendMsgClick(object sender, EventArgs e)
        {
            string msg = txtSendMsg.Text;
            if (msg.Length == 0)
            {
                MessageBox.Show(Resources.MainForm_BtnSendMsgClick_);
                return;
            }
            ListBox.SelectedIndexCollection indexs = listChooseClient.SelectedIndices;
            for (int i = 0; i < indexs.Count; i++)
            {
                int index = indexs[i];
                var userName = (string)listChooseClient.Items[index];
                Socket user = _userList.FirstOrDefault(s => s.RemoteEndPoint.ToString() == userName);
                if (user != null)
                {
                    SendToClient(user, msg);
                }
            }
        }

        private void MainFormFormClosing(object sender, FormClosingEventArgs e)
        {
            StopServer();
        }

        /// <summary>开启服务器</summary>
        public void StartServer(IPAddress ip, int port)
        {
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _socket.Bind(new IPEndPoint(ip, port));
            _socket.Listen(5);
        }

        /// <summary>接收客户端连接</summary>
        private void ListenClientConnect()
        {
            while (true)
            {
                Socket newSocket = null;
                try
                {
                    newSocket = _socket.Accept();
                }
                catch (SocketException ex)
                {
                    AddTalkMessage(ex.ToString());
                }
                if (newSocket == null)
                {
                    continue;
                }

                //每接受一个客户端连接,就创建一个对应的线程循环接收该客户端发来的信息
                var threadReceive = new Thread(ReceiveData);
                threadReceive.Start(newSocket);
                _userList.Add(newSocket);

                AddListUser(newSocket.RemoteEndPoint.ToString());
                AddTalkMessage(string.Format("{0}： [{1}]进入", DateTime.Now.ToShortTimeString(),
                                             newSocket.RemoteEndPoint));

                ChangeConnectNum(_userList.Count + "");
                SendToClient(newSocket, "Hello,I am server...");
            }
        }

        /// <summary>
        /// 处理接收的客户端数据
        /// </summary>
        /// <param name="userState">客户端信息</param>
        private void ReceiveData(object userState)
        {
            var user = (Socket)userState;
            string remoteEndPoint = user.RemoteEndPoint.ToString();
            while (true)
            {
                var byteMessage = new byte[1024];
                try
                {
                    int msgLength = user.Receive(byteMessage);
                    AddTalkMessage(string.Format("{0}说：{1}",
                                                 remoteEndPoint, Encoding.UTF8.GetString(byteMessage, 0, msgLength)));
                }
                catch
                {
                    AddTalkMessage(string.Format("{0}： [{1}]已注销登录", DateTime.Now.ToShortTimeString(), remoteEndPoint));
                    RemoveListUser(remoteEndPoint);
                    RemoveUser(user);
                    ChangeConnectNum(_userList.Count + "");
                    break;
                }
            }
        }

        /// <summary>在在线用户列表中删除一个用户</summary>
        private void RemoveListUser(string remoteEndPoint)
        {
            if (listChooseClient.InvokeRequired)
            {
                MessageDelegate d = RemoveListUser;
                listChooseClient.Invoke(d, new object[] { remoteEndPoint });
            }
            else
            {
                for (int i = 0; i < listChooseClient.Items.Count; i++)
                {
                    object item = listChooseClient.Items[i];
                    if ((string)item != remoteEndPoint) continue;
                    listChooseClient.Items.Remove(item);
                    break;
                }
            }
        }

        /// <summary>改变用户连接数为在线用户数</summary>
        private void ChangeConnectNum(string connectNum)
        {
            if (labelConnectNum.InvokeRequired)
            {
                MessageDelegate d = ChangeConnectNum;
                labelConnectNum.Invoke(d, new object[] { connectNum });
            }
            else
            {
                labelConnectNum.Text = connectNum;
            }
        }

        /// <summary>在在线用户列表中增加一个用户</summary>
        private void AddListUser(string userName)
        {
            if (listChooseClient.InvokeRequired)
            {
                MessageDelegate d = AddListUser;
                listChooseClient.Invoke(d, new object[] { userName });
            }
            else
            {
                listChooseClient.Items.Add(userName);
            }
        }

        /// <summary> 在txtMsg中追加聊天信息</summary>
        private void AddTalkMessage(string message)
        {
            if (txtMsg.InvokeRequired)
            {
                MessageDelegate d = AddTalkMessage;
                txtMsg.Invoke(d, new object[] { message });
            }
            else
            {
                try
                {
                    txtMsg.AppendText(message + Environment.NewLine);
                    txtMsg.ScrollToCaret();
                }
                catch
                {
                    Application.Exit();
                }
            }
        }

        /// <summary>
        /// 发送message给user
        /// </summary>
        /// <param name="user">指定发给哪个用户</param>
        /// <param name="message">信息内容</param>
        private void SendToClient(Socket user, string message)
        {
            try
            {
                user.Send(Encoding.UTF8.GetBytes(message));
                AddTalkMessage(string.Format("向[{0}]发送：{1}",
                                             user.RemoteEndPoint, message));
            }
            catch
            {
                AddTalkMessage(string.Format("向[{0}]发送信息失败",
                                             user.RemoteEndPoint));
            }
        }

        /// <summary>移除用户</summary>
        /// <param name="user">指定要删除的用户</param>
        private void RemoveUser(Socket user)
        {
            _userList.Remove(user);
            user.Shutdown(SocketShutdown.Both);
            user.Close();
        }

        /// <summary>关闭服务器</summary>
        public void StopServer()
        {
            foreach (Socket socket in _userList)
            {
                socket.Shutdown(SocketShutdown.Both);
            }
            _myThread.Abort();
            _socket.Close();
        }

        #region Nested type: MessageDelegate

        private delegate void MessageDelegate(string message);

        #endregion
    }
}